#include "q_shared.h"
#ifdef _WIN32
#pragma once
#define WIN32_LEAN_AND_MEAN
#define NOGDI //don't make me do this the hard way
#include <windows.h>
#else
#ifndef __BG_HOOKS_H
#define __BG_HOOKS_H
#endif
#endif

#if MAC_PORT
#include <sys/mman.h>
#endif

#ifdef _WIN32
#define WIN32_OR_LINUX
#endif
#ifdef _LINUX
#define WIN32_OR_LINUX
#endif

typedef struct hookEntry_s
{
	const unsigned int hookPosition; // The code we're patching
	unsigned char  origBytes[5]; // What it originally was
	unsigned char  hookOpcode;  // CALL or JMP
	const unsigned int hookForward; // Function to direct the control flow into
	const char   *name;   // Long name of the hook
} hookEntry_t;

typedef struct {
	int addr;
	int size;
	char origbytes[24];
} PatchData_t;

typedef enum {
	PATCH_JUMP,
	PATCH_CALL,
} PatchType_e;

PatchData_t *BG_PlacePatch( int type, unsigned int address, unsigned int destination );
void BG_RemovePatch(PatchData_t **patch);

/*#ifndef _PROXYDLL
typedef enum { true, false } bool;
#endif*/

qboolean UnlockMemory( int address, int size );
qboolean LockMemory( int address, int size );
void PlaceHook( hookEntry_t *hook );
void RemoveHook( const hookEntry_t *hook );

#define PATCH( address, type, to )		\
{									\
	UnlockMemory( address, 1 );		\
	*(type *)address = (type)to;	\
	LockMemory( address, 1 );		\
}


typedef enum {
	HOOK_G_CALLSPAWN1,
	HOOK_G_CALLSPAWN2,
	HOOK_G_CALLSPAWN3,
	HOOK_FIXED_SABER_CRASH,
	HOOK_MAX,
} gameHooks_t;

PatchData_t *hooks[HOOK_MAX];

#ifndef __PROXYDLL
#define HOOK_CALL(a, b, c)	hooks[a] = BG_PlacePatch(PATCH_CALL, b, ( unsigned int ) c)
#define HOOK_JUMP(a, b, c)	hooks[a] = BG_PlacePatch(PATCH_JUMP, b, ( unsigned int ) c)
#else
#define HOOK_CALL(a, b, c)	proxyHooks[a] = BG_PlacePatch(PATCH_CALL, b, ( unsigned int ) c)
#define HOOK_JUMP(a, b, c)	proxyHooks[a] = BG_PlacePatch(PATCH_JUMP, b, ( unsigned int ) c)
#endif